package com.gitee.feizns.quickstart.domain.vo;

import com.gitee.feizns.dynamic.Objs;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.function.Supplier;

/**
 * 作为控制器返回值的领域对象
 * @author feizns
 * @since 2019/7/7
 */
@Data
@Accessors(chain = true)
public class Ret<T> {

    /**
     * 响应成功默认的消息
     */
    public static final String OK = "ok";

    /**
     * 响应成功默认的响应码
     */
    public static final int OK_CODE = 200;

    /**
     * 服务器内部错误默认响应码
     */
    public static final int INTERNAL_SERVER_ERROR = 500;

    /**
     * 请求错误默认响应码
     */
    public static final int BAD_REQUEST = 400;

    /**
     * 未经 授权
     */
    public static final int UNAUTHORIZED = 401;

    /**
     * 响应码
     */
    private Integer code;

    /**
     * 响应消息
     */
    private String msg;

    /**
     * 数据
     */
    private T data;

    /**
     * 如果当前的data是一个单元素的数组则会被解开数组
     * @return {@link Ret}
     */
    public Ret<?> unpack() {
        Object data = this.data;
        if ( this.data != null )
            data = Objs.unpack(this.data);
        return Ret.ok(data);
    }

    //============================OK===============================
    //============================OK===============================
    //============================OK===============================

    /**
     * 返回ok 并指定数据
     * @param data 数据
     */
    public Ret(T data) {
        this.data = data;
    }

    /**
     * 无数据的响应
     * @return {@link Ret}
     * @param <T> 数据类型
     */
    public static <T> Ret<T> ok() {
        return ok((T) null);
    }

    /**
     * ok 的数据响应
     * @param data 数据
     * @return {@link Ret}
     * @param <T> 类型
     */
    public static <T> Ret<T> ok(T data) {
        return create(OK_CODE, OK, data);
    }

    /**
     * ok 的数据响应
     * @param supplier 数据提供者{@link Supplier}
     * @return {@link Ret}
     * @param <T> 数据类型
     */
    public static <T> Ret<T> ok(Supplier<T> supplier) {
        return ok(supplier.get());
    }

    /**
     * ok 响应
     * @param callback 回调函数,{@link Runnable}
     * @return {@link Ret}
     */
    public static Ret<Void> ok(Runnable callback) {
        callback.run();
        return ok();
    }

    //============================ERROR===============================
    //============================ERROR===============================
    //============================ERROR===============================

    /**
     * 错误请求
     * @return {@link Ret }<{@link Void }>
     */
    public static <T> Ret<T> badRequest(String msg) {
        return new Ret<>(BAD_REQUEST, msg, null);
    }

    /**
     * 错误请求
     * @param msg 味精
     * @param data 数据
     * @return {@link Ret }<{@link T }>
     */
    public static <T> Ret<T> badRequest(String msg, T data) {
        return new Ret<>(BAD_REQUEST, msg, data);
    }

    /**
     * 未经 授权
     * @param msg 味精
     * @return {@link Ret }<{@link T }>
     */
    public static <T> Ret<T> unauthorized(String msg) {
        return new Ret<>(UNAUTHORIZED, msg, null);
    }

    /**
     * 未经 授权
     * @param msg 味精
     * @param data 数据
     * @return {@link Ret }<{@link T }>
     */
    public static <T> Ret<T> unauthorized(String msg, T data) {
        return new Ret<>(UNAUTHORIZED, msg, data);
    }

    /**
     * 错误响应
     * @param msg 错误消息
     * @return {@link Ret}
     * @param <T> 数据类型
     */
    public static <T> Ret<T> error(String msg) {
        return error(INTERNAL_SERVER_ERROR, msg);
    }

    /**
     * 错误响应
     * @param msg 错误消息
     * @return {@link Ret}
     * @param <T> 数据类型
     */
    public static <T> Ret<T> error(Integer code, String msg) {
        return create(code, msg, null);
    }

    /**
     * 错误响应
     * @param code 错误码
     * @param msg 错误消息
     * @param data 数据
     * @return {@link Ret}
     * @param <T> 数据类型
     */
    public static <T> Ret<T> error(Integer code, String msg, T data) {
        return create(code, msg, data);
    }


    //============================CREATE===============================
    //============================CREATE===============================
    //============================CREATE===============================

    public Ret(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    /**
     * 创建
     * @param code 响应码
     * @param msg 消息
     * @param data 数据
     * @return {@link Ret}
     * @param <T> 数据类型
     */
    public static <T> Ret<T> create(Integer code, String msg, T data) {
        return new Ret<>(code, msg, data);
    }

}
